package com.zjhn.ds.task;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zjhn.ds.common.annotate.IgnoreTenant;
import com.zjhn.ds.domain.entity.jlw.DailyProduceStatistics;
import com.zjhn.ds.domain.entity.jlw.MachineChange;
import com.zjhn.ds.domain.entity.jlw.MaintenanceInfo;
import com.zjhn.ds.domain.entity.jlw.Proofing;
import com.zjhn.ds.domain.entity.jlw.ReportRecord;
import com.zjhn.ds.domain.entity.jlw.SpotCheck;
import com.zjhn.ds.domain.vo.ChangTimeVo;
import com.zjhn.ds.domain.vo.StationVo;
import com.zjhn.ds.mapper.MachineChangeMapper;
import com.zjhn.ds.mapper.MaintenanceInfoMapper;
import com.zjhn.ds.mapper.ProofingMapper;
import com.zjhn.ds.mapper.ReportRecordMapper;
import com.zjhn.ds.mapper.SpotCheckMapper;
import com.zjhn.ds.service.DailyProduceStatisticsService;
import com.zjhn.ds.utils.CommonUtil;
import com.zjhn.ds.utils.base.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * TODO 类作用描述
 *
 * @author sxt
 * @date 2024/9/7
 */
@Slf4j
@Configuration
public class CapacityStatisticsTask {

    @Resource
    private ProofingMapper proofingMapper;
    @Resource
    private ReportRecordMapper reportRecordMapper;
    @Resource
    private MachineChangeMapper machineChangeMapper;
    @Resource
    private SpotCheckMapper spotCheckMapper;
    @Resource
    private CommonUtil commonUtil;
    @Resource
    private MaintenanceInfoMapper maintenanceInfoMapper;

    @Resource
    private DailyProduceStatisticsService dailyProduceStatisticsService;

    @IgnoreTenant
    @Scheduled(cron = "0 40 7,19 * * ?")
    public void statics() {
        try {
            String hhStr = DateUtil.formatDateToString(new Date(), "HH");
            int hour = Integer.parseInt(hhStr);

            String workshopClassesId;
            String startTime;
            String endTime;
            String recordDate;

            String date = DateUtil.formatDateToString(new Date(), DateUtil.DATE_FORMAT);
            String lastDay = DateUtil.formatDateToString(
                    DateUtil.dateAddDay(
                            DateUtil.formatStringToDate(date, DateUtil.DATE_FORMAT), -1),
                    DateUtil.DATE_FORMAT);
            if (hour > 12) {
                // 记录白班
//                WorkshopClasses workshopClasses = workshopClassesMapper.selectById("d36083b4fcc64a93b894524c3e083ad3");
                startTime = date + " 07:40:00";
                endTime = date + " 19:40:00";
                workshopClassesId = "d36083b4fcc64a93b894524c3e083ad3";
                recordDate = date;
            } else {
                // 记录夜班
//                WorkshopClasses workshopClasses = workshopClassesMapper.selectById("d11b59abb58447ce84f7703adb35aa4e");
                startTime = lastDay + " 19:40:00";
                endTime = date + " 07:40:00";
                workshopClassesId = "d11b59abb58447ce84f7703adb35aa4e";
                recordDate = lastDay;
            }

            List<DailyProduceStatistics> list = new ArrayList<>();

            queryCurrent(recordDate, workshopClassesId, startTime, endTime, list);

            if (!list.isEmpty())
                dailyProduceStatisticsService.saveBatch(list);
        } catch (Exception e) {
            log.error("====[ERROR]====CapacityStatisticsTask====statics 异常:{}", e.getMessage());
        }
    }

    public void queryCurrent(String date, String workshopClassId, String startTime, String endTime, List<DailyProduceStatistics> list) {
        List<ReportRecord> allReportRecords = reportRecordMapper.selectList(
                new QueryWrapper<ReportRecord>()
                        .eq("deleted", 0)
                        .between("create_time", startTime, endTime));

        if (!allReportRecords.isEmpty()) {
            Map<String, List<ReportRecord>> group = allReportRecords.stream().collect(Collectors.groupingBy(ReportRecord::getStationId));
            Set<String> stationIds = group.keySet();

            // 获取维修+改机+打样记录
            Map<String, List<MachineChange>> machineGroup = new HashMap<>();
            Map<String, List<MaintenanceInfo>> maintenanceGroup = new HashMap<>();
            Map<String, List<Proofing>> proofingGroup = new HashMap<>();
            Map<String, List<ChangTimeVo>> changeTimeMap = new HashMap<>();
            List<MaintenanceInfo> maintenanceInfos = maintenanceInfoMapper.selectList(new QueryWrapper<MaintenanceInfo>()
                    .eq("finish", 1)
                    .in("station_id", stationIds)
                    .between("maintenance_time", startTime, endTime)
            );
            if (!maintenanceInfos.isEmpty())
                maintenanceGroup.putAll(maintenanceInfos.stream().collect(Collectors.groupingBy(MaintenanceInfo::getStationId)));
            List<Proofing> proofings = proofingMapper.selectList(new QueryWrapper<Proofing>()
                    .eq("finish", 1)
                    .in("station_id", stationIds)
                    .between("proofing_time", startTime, endTime)
            );
            if (!proofings.isEmpty())
                proofingGroup.putAll(proofings.stream().collect(Collectors.groupingBy(Proofing::getStationId)));
            List<MachineChange> machineChanges = machineChangeMapper.selectList(new QueryWrapper<MachineChange>()
                    .eq("finish", 1)
                    .in("station_id", stationIds)
                    .between("change_time", startTime, endTime)
                    .orderByAsc("change_time")
            );
            if (!machineChanges.isEmpty()) {
                machineGroup.putAll(machineChanges.stream().collect(Collectors.groupingBy(MachineChange::getStationId)));

                for (Map.Entry<String, List<MachineChange>> entry : machineGroup.entrySet()) {
                    String stationId = entry.getKey();
                    List<MachineChange> changes = entry.getValue();
                    changes.sort(Comparator.comparing(MachineChange::getChangeTime));
                    // 改机分组
                    List<ChangTimeVo> changeTimeList = new ArrayList<>();
                    changeTimeList.add(ChangTimeVo.builder().changeTime(startTime).build());
                    changeTimeList.addAll(
                            changes.stream()
                                    .map(c -> ChangTimeVo.builder()
                                            .changeTime(c.getChangeTime()).machineChange(c).build())
                                    .collect(Collectors.toList())
                    );
                    changeTimeList.add(ChangTimeVo.builder().changeTime(endTime).build());
                    changeTimeMap.put(stationId, changeTimeList);
                }
            }

            // 获取编制检修记录
            List<SpotCheck> spotChecks = spotCheckMapper.selectList(
                    new QueryWrapper<SpotCheck>()
                            .in("station_id", stationIds)
                            .eq("deleted", 0)
                            .between("create_time", startTime, endTime));
            Map<String, List<SpotCheck>> stationSpotCheckGroup = new HashMap<>();
            if (!spotChecks.isEmpty())
                stationSpotCheckGroup.putAll(spotChecks.stream().collect(Collectors.groupingBy(SpotCheck::getStationId)));

            Map<String, List<ReportRecord>> userNoGroup = allReportRecords.stream().collect(Collectors.groupingBy(ReportRecord::getUserNo));
            for (Map.Entry<String, List<ReportRecord>> userNoEntry : userNoGroup.entrySet()) {
                String userNo = userNoEntry.getKey();
                List<ReportRecord> reportRecords = userNoEntry.getValue();

                Map<String, List<ReportRecord>> stationReportGroup = reportRecords.stream().collect(Collectors.groupingBy(ReportRecord::getStationId));
                for (Map.Entry<String, List<ReportRecord>> entry : stationReportGroup.entrySet()) {
                    String stationId = entry.getKey();
                    List<ReportRecord> reports = entry.getValue();

                    StationVo stationById = commonUtil.getStationById(stationId);
                    String realName = reports.get(0).getRealName();
                    List<ChangTimeVo> changeTimeList = changeTimeMap.get(stationId);
                    if (changeTimeList == null) {
                        // 单只耗时
                        Double singleCostMinute = machineChangeMapper.selectLatestSingleCost(stationId, endTime);

                        BigDecimal singleCost = singleCostMinute == null ?
                                null :
                                BigDecimal.valueOf(singleCostMinute)
                                        .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

                        BigDecimal maintenanceChangeTime = BigDecimal.ZERO;
                        List<MachineChange> changes = machineGroup.get(stationId);
                        if (changes != null)
                            maintenanceChangeTime = maintenanceChangeTime.add(changes.stream().map(MachineChange::getSpendTime).reduce(BigDecimal.ZERO, BigDecimal::add));
                        List<MaintenanceInfo> maintenances = maintenanceGroup.get(stationId);
                        if (maintenances != null)
                            maintenanceChangeTime = maintenanceChangeTime.add(maintenances.stream().map(MaintenanceInfo::getSpendTime).reduce(BigDecimal.ZERO, BigDecimal::add));
                        List<Proofing> proofingList = proofingGroup.get(stationId);
                        if (proofingList != null)
                            maintenanceChangeTime = maintenanceChangeTime.add(proofingList.stream().map(Proofing::getSpendTime).reduce(BigDecimal.ZERO, BigDecimal::add));
                        // 修机器时间
                        maintenanceChangeTime = maintenanceChangeTime.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

                        // 运转时间
                        BigDecimal operateTime = BigDecimal.valueOf(60 * 12 - 15 * 2).subtract(maintenanceChangeTime);

                        // 预计产能
                        BigDecimal expectProduceQty = null;
                        if (singleCost != null)
                            expectProduceQty = operateTime.divide(singleCost, 2, RoundingMode.HALF_UP)
                                    .divide(BigDecimal.valueOf(2), 2, RoundingMode.HALF_UP);

                        // 实际产量
                        BigDecimal actualProduceQty = reports.stream().map(ReportRecord::getBookJobQty).reduce(BigDecimal.ZERO, BigDecimal::add);

                        // 不良数
                        BigDecimal defectsQty = BigDecimal.ZERO;
                        List<SpotCheck> spots = stationSpotCheckGroup.get(stationId);
                        if (spots != null)
                            defectsQty = BigDecimal.valueOf(spots.stream().map(SpotCheck::getRejectQty).reduce(0, Integer::sum));

                        // 产能效率
                        BigDecimal produceRate = null;
                        if (expectProduceQty != null)
                            produceRate = actualProduceQty.multiply(BigDecimal.valueOf(100)).divide(expectProduceQty, 2, RoundingMode.HALF_UP);

                        // 不良率
                        BigDecimal defectsRate = null;
                        if (actualProduceQty.compareTo(BigDecimal.ZERO) != 0)
                            defectsRate = defectsQty.multiply(BigDecimal.valueOf(100)).divide(actualProduceQty, 2, RoundingMode.HALF_UP);


                        list.add(DailyProduceStatistics.builder()
                                .date(date)
                                .workshopClassId(workshopClassId)
                                .stationId(stationById == null ? null : stationById.getId())
                                .stationCode(stationById == null ? null : stationById.getStationCode())
                                .stationName(stationById == null ? null : stationById.getStationName())
                                .singleCost(singleCost)
                                .operateTime(operateTime)
                                .maintenanceChangeTime(maintenanceChangeTime)
                                .expectProduceQty(expectProduceQty)
                                .actualProduceQty(actualProduceQty)
                                .defectsQty(defectsQty)
                                .produceRate(produceRate)
                                .defectsRate(defectsRate)
                                .userNo(userNo)
                                .realName(realName)
                                .startTime(startTime)
                                .endTime(endTime)
                                .build());
                    } else {
                        // 改机存在
                        BigDecimal restTime = BigDecimal.valueOf(15 * 2);
                        String timeStart = null;
                        String timeEnd;
                        ChangTimeVo preVo = null;
                        for (int i = 0; i < changeTimeList.size(); i++) {
                            ChangTimeVo changTimeVo = changeTimeList.get(i);
                            if (timeStart == null) {
                                timeStart = changTimeVo.getChangeTime();
                                preVo = changTimeVo;
                                continue;
                            }

                            timeEnd = changTimeVo.getChangeTime();
                            // 获取对应时间段的报工记录
                            Date timeStartDate = DateUtil.formatStringToDate(timeStart);
                            Date timeEndDate = DateUtil.formatStringToDate(timeEnd);

                            List<ReportRecord> filter = reports.stream()
                                    .filter(obj -> {
                                        Date objDate = obj.getCreateTime();
                                        return objDate.compareTo(timeStartDate) >= 0 && objDate.compareTo(timeEndDate) < 0;
                                    })
                                    .collect(Collectors.toList());

                            if (filter.isEmpty()) {
                                timeStart = changTimeVo.getChangeTime();
                                preVo = changTimeVo;
                                continue;
                            }

                            /*
                             * 报工处理
                             */

                            // 单只耗时
                            Double singleCostMinute = machineChangeMapper.selectLatestSingleCost(stationId, timeEnd);
                            BigDecimal singleCost = singleCostMinute == null ?
                                    null :
                                    BigDecimal.valueOf(singleCostMinute)
                                            .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

                            BigDecimal maintenanceChangeTime = BigDecimal.ZERO;
                            // 改机时间
                            MachineChange machineChange = preVo.getMachineChange();
                            if (machineChange != null)
                                maintenanceChangeTime = maintenanceChangeTime.add(machineChange.getSpendTime());
                            // 维修时间
                            List<MaintenanceInfo> maintenances = maintenanceGroup.get(stationId);
                            if (maintenances != null) {
                                List<MaintenanceInfo> filterMaintenanceInfo = maintenances.stream()
                                        .filter(obj -> {
                                            Date objDate = DateUtil.formatStringToDate(obj.getMaintenanceTime());
                                            return objDate.compareTo(timeStartDate) >= 0 && objDate.compareTo(timeEndDate) < 0;
                                        })
                                        .collect(Collectors.toList());
                                if (!filterMaintenanceInfo.isEmpty())
                                    maintenanceChangeTime = maintenanceChangeTime
                                            .add(filterMaintenanceInfo.stream()
                                                    .map(MaintenanceInfo::getSpendTime)
                                                    .reduce(BigDecimal.ZERO, BigDecimal::add));
                            }
                            // 打样时间
                            List<Proofing> proofingList = proofingGroup.get(stationId);
                            if (proofingList != null) {
                                List<Proofing> filterProofingList = proofingList.stream()
                                        .filter(obj -> {
                                            Date objDate = DateUtil.formatStringToDate(obj.getProofingTime());
                                            return objDate.compareTo(timeStartDate) >= 0 && objDate.compareTo(timeEndDate) < 0;
                                        })
                                        .collect(Collectors.toList());
                                if (!filterProofingList.isEmpty())
                                    maintenanceChangeTime = maintenanceChangeTime
                                            .add(filterProofingList.stream()
                                                    .map(Proofing::getSpendTime)
                                                    .reduce(BigDecimal.ZERO, BigDecimal::add));
                            }
                            // 修机器时间
                            maintenanceChangeTime = maintenanceChangeTime.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

                            // 运转时间
                            Long intervalMinutes = DateUtil.intervalMinutes(timeStart, timeEnd);
                            BigDecimal operateTime =
                                    BigDecimal.valueOf(intervalMinutes)
                                            .subtract(maintenanceChangeTime);
                            if (restTime != null) {
                                operateTime = operateTime.subtract(restTime);
                                restTime = null;
                            }

                            // 预计产能
                            BigDecimal expectProduceQty = null;
                            if (singleCost != null)
                                expectProduceQty = operateTime.divide(singleCost, 2, RoundingMode.HALF_UP)
                                        .divide(BigDecimal.valueOf(2), 2, RoundingMode.HALF_UP);

                            // 实际产量
                            BigDecimal actualProduceQty = filter.stream().map(ReportRecord::getBookJobQty).reduce(BigDecimal.ZERO, BigDecimal::add);

                            // 不良数
                            BigDecimal defectsQty = BigDecimal.ZERO;
                            List<SpotCheck> spots = stationSpotCheckGroup.get(stationId);
                            if (spots != null) {
                                List<SpotCheck> filterSpots = spots.stream()
                                        .filter(obj -> {
                                            Date objDate = obj.getCreateTime();
                                            return objDate.compareTo(timeStartDate) >= 0 && objDate.compareTo(timeEndDate) < 0;
                                        })
                                        .collect(Collectors.toList());
                                if (!filterSpots.isEmpty())
                                    defectsQty = BigDecimal.valueOf(filterSpots.stream().map(SpotCheck::getRejectQty).reduce(0, Integer::sum));
                            }

                            // 产能效率
                            BigDecimal produceRate = null;
                            if (expectProduceQty != null)
                                produceRate = actualProduceQty.multiply(BigDecimal.valueOf(100)).divide(expectProduceQty, 2, RoundingMode.HALF_UP);

                            // 不良率
                            BigDecimal defectsRate = null;
                            if (actualProduceQty.compareTo(BigDecimal.ZERO) != 0)
                                defectsRate = defectsQty.multiply(BigDecimal.valueOf(100)).divide(actualProduceQty, 2, RoundingMode.HALF_UP);

                            list.add(DailyProduceStatistics.builder()
                                    .date(date)
                                    .workshopClassId(workshopClassId)
                                    .stationId(stationById == null ? null : stationById.getId())
                                    .stationCode(stationById == null ? null : stationById.getStationCode())
                                    .stationName(stationById == null ? null : stationById.getStationName())
                                    .singleCost(singleCost)
                                    .operateTime(operateTime)
                                    .maintenanceChangeTime(maintenanceChangeTime)
                                    .expectProduceQty(expectProduceQty)
                                    .actualProduceQty(actualProduceQty)
                                    .defectsQty(defectsQty)
                                    .produceRate(produceRate)
                                    .defectsRate(defectsRate)
                                    .userNo(userNo)
                                    .realName(realName)
                                    .startTime(timeStart)
                                    .endTime(timeEnd)
                                    .build());

                            timeStart = timeEnd;
                            preVo = changTimeVo;
                        }
                    }
                }
            }
        }
    }

}
